home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / sprites / dib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-02  |  13.8 KB  |  590 lines

  1. /*
  2.     dib.c
  3.  
  4.     DIB routines
  5.  
  6. */
  7.  
  8. #include "global.h"
  9.  
  10. //
  11. // Load a DIB file.
  12. // If pszDIB is NULL or empty, a dialog is presented to choose the file
  13. // The DIB structure pointed to by pDIB is filled in with the info
  14. // on the DIB.  A single memory chunk is used for the whole DIB 
  15. // keeping the DIB in CF_DIB (packed DIB) format.
  16. //
  17.  
  18. PDIB LoadDIB(LPSTR pszPath)
  19. {
  20.     char szFile[_MAX_PATH];
  21.     int fd;
  22.     OFSTRUCT os;
  23.     BITMAPFILEHEADER BmpFileHdr;
  24.     BITMAPINFOHEADER BmpInfoHdr;
  25.     BITMAPCOREHEADER BmpCoreHdr;
  26.     WORD wColors, wColorTableSize, wBytes, w;
  27.     DWORD dwBISize, dwBitsSize, dwBytes, dwSize;
  28.     LPBITMAPINFO pBmpInfo = NULL;
  29.     HPSTR pBits = NULL;
  30.     BOOL bIsPM = FALSE;
  31.     RGBTRIPLE rgbt;
  32.     LPRGBQUAD lpRGB;
  33.  
  34.     if (!pszPath || !lstrlen(pszPath)) {
  35.  
  36.         //
  37.         // Show the file open dialog
  38.         //
  39.  
  40.         if (!PromptForFileName(hwndMain, 
  41.                                hAppInstance, 
  42.                                szFile,
  43.                                sizeof(szFile), 
  44.                                "Open File", 
  45.                                szOpenFilter,
  46.                                "dib",
  47.                                PFFN_OPENFILE | PFFN_UPPERCASE)) {
  48.             return NULL;
  49.         }
  50.  
  51.     } else {
  52.  
  53.         lstrcpy(szFile, pszPath);
  54.  
  55.     }
  56.  
  57.     //
  58.     // try to open the file in read mode
  59.     //
  60.  
  61.     fd = OpenFile(szFile, &os, OF_READ);
  62.     if (fd < 1) {
  63.         dprintf1("Failed to open %s", (LPSTR)szFile);
  64.         goto $abort;
  65.     }
  66.  
  67.     dprintf2("Loading: %s", (LPSTR)szFile);
  68.  
  69.     //
  70.     // read the file header to get the file size and to
  71.     // find where the bits start in the file
  72.     //
  73.  
  74.     wBytes = _lread(fd, (LPSTR)&BmpFileHdr, sizeof(BmpFileHdr)); 
  75.     if (wBytes != sizeof(BmpFileHdr)) {
  76.         dprintf1("Failed to read file header");
  77.         goto $abort;
  78.     }
  79.  
  80.     //
  81.     // check we have the magic 'BM' at the start
  82.     //
  83.  
  84.     if (BmpFileHdr.bfType != 0x4D42) {
  85.         dprintf1("Not a bitmap file");
  86.         goto $abort;
  87.     }
  88.  
  89.     //
  90.     // make a wild guess that the file is in Windows DIB
  91.     // format and read the BITMAPINFOHEADER.  If it turns
  92.     // out to be a PM DIB file we'll convert it later.
  93.     //
  94.  
  95.     wBytes = _lread(fd, (LPSTR)&BmpInfoHdr, sizeof(BmpInfoHdr)); 
  96.     if (wBytes != sizeof(BmpInfoHdr)) {
  97.         dprintf1("Failed to read BITMAPINFOHEADER");
  98.         goto $abort;
  99.     }
  100.  
  101.     //
  102.     // check we got a real Windows DIB file
  103.     //
  104.  
  105.     if (BmpInfoHdr.biSize != sizeof(BITMAPINFOHEADER)) {
  106.         dprintf3("File is not Windows DIB format");
  107.         if (BmpInfoHdr.biSize != sizeof(BITMAPCOREHEADER)) {
  108.             dprintf1("File is not Windows or PM DIB format");
  109.             goto $abort;
  110.         }
  111.  
  112.         //
  113.         // set a flag to convert PM file to Win format later
  114.         //
  115.  
  116.         bIsPM = TRUE;
  117.  
  118.         //
  119.         // back up the file pointer and read the BITMAPCOREHEADER
  120.         // and create the BITMAPINFOHEADER from it
  121.         //
  122.  
  123.         _llseek(fd, sizeof(BITMAPFILEHEADER), SEEK_SET);
  124.  
  125.         wBytes = _lread(fd, (LPSTR)&BmpCoreHdr, sizeof(BmpCoreHdr)); 
  126.         if (wBytes != sizeof(BmpCoreHdr)) {
  127.             dprintf1("Failed to read BITMAPCOREHEADER");
  128.             goto $abort;
  129.         }
  130.  
  131.         BmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER);
  132.         BmpInfoHdr.biWidth = (DWORD) BmpCoreHdr.bcWidth;
  133.         BmpInfoHdr.biHeight = (DWORD) BmpCoreHdr.bcHeight;
  134.         BmpInfoHdr.biPlanes = BmpCoreHdr.bcPlanes;
  135.         BmpInfoHdr.biBitCount = BmpCoreHdr.bcBitCount;
  136.         BmpInfoHdr.biCompression = BI_RGB;
  137.         BmpInfoHdr.biSizeImage = 0;
  138.         BmpInfoHdr.biXPelsPerMeter = 0;
  139.         BmpInfoHdr.biYPelsPerMeter = 0;
  140.         BmpInfoHdr.biClrUsed = 0;
  141.         BmpInfoHdr.biClrImportant = 0;
  142.  
  143.     }
  144.  
  145.     //
  146.     // ok so we got a real DIB file so work out 
  147.     // how much memory we need for the BITMAPINFO
  148.     // structure, color table and bits.  Allocate it,
  149.     // copy the BmpInfoHdr we have so far 
  150.     // and then read in the color table from the file
  151.     //
  152.  
  153.     wColors = NumDIBColorEntries((LPBITMAPINFO) &BmpInfoHdr);
  154.     wColorTableSize = wColors * sizeof(RGBQUAD);
  155.     dwBitsSize = BmpFileHdr.bfSize - BmpFileHdr.bfOffBits;
  156.     dwBISize = (DWORD) sizeof(BITMAPINFOHEADER)    
  157.            + (DWORD) wColorTableSize;
  158.     dwSize = dwBISize + dwBitsSize;
  159.  
  160.     if (dwSize > 65536L) {
  161.         dprintf2("WARNING: DIB > 64k");
  162.     }
  163.  
  164.     //
  165.     // allocate and lock the memory
  166.     //
  167.  
  168.     pBmpInfo = (LPBITMAPINFO) ALLOCATE(dwSize);
  169.     if (!pBmpInfo) {
  170.         dprintf1("Out of memory for DIB");
  171.         goto $abort;
  172.     }
  173.  
  174.     //
  175.     // copy the header we already have
  176.     //
  177.  
  178.     hmemcpy((HPSTR) pBmpInfo, (HPSTR) &BmpInfoHdr, sizeof(BITMAPINFOHEADER));
  179.  
  180.     //
  181.     // now read the color table in from the file
  182.     //
  183.  
  184.     if (bIsPM == FALSE) {
  185.  
  186.         //
  187.         // read the color table from the file
  188.         //
  189.  
  190.         wBytes = _lread(fd,
  191.                         ((LPSTR) pBmpInfo) + sizeof(BITMAPINFOHEADER),
  192.                         wColorTableSize);
  193.     
  194.         if (wBytes != wColorTableSize) {
  195.             dprintf1("Failed to read color table");
  196.             goto $abort;
  197.         }
  198.  
  199.     } else {
  200.  
  201.         //
  202.         // read each color table entry in turn and convert it
  203.         // to Win DIB format as we go
  204.         //
  205.  
  206.         lpRGB = (LPRGBQUAD) ((LPSTR) pBmpInfo + sizeof(BITMAPINFOHEADER));
  207.         for (w=0; w<wColors; w++) {
  208.             wBytes = _lread(fd, (LPSTR) &rgbt, sizeof(RGBTRIPLE));
  209.             if (wBytes != sizeof(RGBTRIPLE)) {
  210.                 dprintf1("Failed to read RGBTRIPLE");
  211.                 goto $abort;
  212.             }
  213.             lpRGB->rgbBlue = rgbt.rgbtBlue;
  214.             lpRGB->rgbGreen = rgbt.rgbtGreen;
  215.             lpRGB->rgbRed = rgbt.rgbtRed;
  216.             lpRGB->rgbReserved = 0;
  217.             lpRGB++;
  218.         }
  219.     }
  220.  
  221.     //
  222.     // now we just have to read the bits from the file
  223.     //
  224.  
  225.     pBits = (LPSTR) pBmpInfo 
  226.           + sizeof(BITMAPINFOHEADER)
  227.           + wColors * sizeof(RGBQUAD);
  228.  
  229.     //
  230.     // seek to the bits in the file
  231.     //
  232.  
  233.     _llseek(fd, BmpFileHdr.bfOffBits, SEEK_SET);
  234.  
  235.     //
  236.     // read the bits
  237.     //
  238.  
  239.     dwBytes = _hread(fd, pBits, dwBitsSize);
  240.     if (dwBytes != dwBitsSize) {
  241.         dprintf1("Failed to read bits");
  242.         goto $abort;
  243.     }
  244.  
  245. #ifdef DEBUG
  246.     ShowInfo(pBmpInfo);
  247. #endif
  248.  
  249.     //
  250.     // done with the file
  251.     //
  252.  
  253.     _lclose(fd);
  254.  
  255.  
  256.     //
  257.     // make sure it's a 256 color DIB
  258.     //
  259.  
  260.     if (pBmpInfo->bmiHeader.biBitCount != 8) {
  261.         Message(0, "%u bit DIBs are not supported", (UINT)pBmpInfo->bmiHeader.biBitCount);
  262.         goto $abort;
  263.     }
  264.  
  265.     //
  266.     // make sure it's not RLE
  267.     //
  268.  
  269.     if (pBmpInfo->bmiHeader.biCompression != BI_RGB) {
  270.         Message(0, "Compressed (RLE) DIBs are not supported");
  271.         goto $abort;
  272.     }
  273.  
  274.     //
  275.     // Copy the return info
  276.     //
  277.  
  278.     return (PDIB) pBmpInfo;
  279.  
  280.  
  281. $abort: // crap out
  282.  
  283.     if (pBmpInfo) FREE(pBmpInfo);
  284.     if (fd >= 1) _lclose(fd);
  285.  
  286.     Message(0, "Unable to load file");
  287.  
  288.     return NULL;
  289. }
  290.  
  291. //
  292. // Delete a DIB
  293. //
  294.  
  295. void DeleteDIB(PDIB pDIB)
  296. {
  297.     if (!pDIB) return;
  298.  
  299.     FREE(pDIB);
  300.  
  301. }
  302.  
  303. //
  304. // Check for a windows DIB
  305. //
  306.  
  307. BOOL IsWinDIB(LPBITMAPINFOHEADER pBIH)
  308. {
  309.     if (pBIH->biSize != sizeof(BITMAPINFOHEADER)) {
  310.         return FALSE;
  311.     }
  312.     return TRUE;
  313. }
  314.  
  315. //
  316. // The the value (color index) of a DIB pixel
  317. // NOTE: DIB scan lines are DWORD aligned.  The scan line 
  318. // storage width may be wider than the scan line image width
  319. // so calc the storage width by rounding the image width 
  320. // to the next highest dword value
  321. //
  322.  
  323. HPSTR GetDIBPixelAddress(PDIB pDIB, int x, int y)
  324. {
  325.     HPSTR p;
  326.     long lWidth;
  327.  
  328.     //
  329.     // make sure it's in range and if not return zero
  330.     //
  331.  
  332.     if ((x < 0)
  333.     || (y < 0)
  334.     || (x >= DIB_WIDTH(pDIB)) 
  335.     || (y >= DIB_HEIGHT(pDIB))) {
  336.         dprintf1("Attempt to get out of range pixel addr");
  337.         return NULL;
  338.     }
  339.  
  340.     //
  341.     // Calculate the scan line storage width
  342.     //
  343.  
  344.     lWidth = DIB_STORAGEWIDTH(pDIB);
  345.  
  346.     ASSERT(lWidth <= DIB_WIDTH(pDIB) + 3);
  347.     ASSERT(lWidth >= DIB_WIDTH(pDIB));
  348.  
  349.     p = (HPSTR) DIB_PBITS(pDIB);
  350.     p += (long)(DIB_HEIGHT(pDIB)-y-1) * lWidth + (long)x;
  351.  
  352.     return p;
  353. }
  354.  
  355. //
  356. // The the value (color index) of a DIB pixel
  357. //
  358.  
  359. BYTE GetDIBPixelValue(PDIB pDIB, int x, int y)
  360. {
  361.     HPSTR p;
  362.  
  363.     p = GetDIBPixelAddress(pDIB, x, y);
  364.  
  365.     if (!p) {
  366.  
  367.         dprintf1("Out of range pixel coords");
  368.         return 0;
  369.     }
  370.  
  371.     return *p;
  372. }
  373.  
  374. //
  375. // Return the Color of a DIB pixel
  376. //
  377.  
  378. COLORREF GetDIBPixelColor(PDIB pDIB, int x, int y)
  379. {
  380.     BYTE value;
  381.     RGBQUAD quad;
  382.     COLORREF clr;
  383.  
  384.     value = GetDIBPixelValue(pDIB, x, y);
  385.     quad = (DIB_PCLRTAB(pDIB))[value];
  386.     clr = RGB(quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
  387.  
  388.     return clr;
  389. }
  390.  
  391. //
  392. // Show some DIB info
  393. //
  394.  
  395. void ShowInfo(LPBITMAPINFO lpBmpInfo)
  396. {
  397.     LPBITMAPINFOHEADER lpBmpInfoHdr;
  398.  
  399.     lpBmpInfoHdr = &lpBmpInfo->bmiHeader;
  400.  
  401.     dprintf4("BITMAPINFOHEADER:");
  402. //  dprintf4("  biSize:          %lu", lpBmpInfoHdr->biSize);
  403.     dprintf4("  biWidth:         %lu", lpBmpInfoHdr->biWidth);
  404.     dprintf4("  biHeight:        %lu", lpBmpInfoHdr->biHeight);
  405.     dprintf4("  biPlanes:        %u", lpBmpInfoHdr->biPlanes);
  406.     dprintf4("  biBitCount:      %u", lpBmpInfoHdr->biBitCount);
  407.     switch (lpBmpInfoHdr->biCompression) {
  408.     case BI_RGB:
  409.         dprintf4("  biCompression:   none");
  410.         break;
  411.     case BI_RLE8:
  412.         dprintf4("  biCompression:   RLE 8");
  413.         break;
  414.     case BI_RLE4:
  415.         dprintf4("  biCompression:   RLE 4");
  416.         break;
  417.     default:
  418.         dprintf4("  biCompression:   unknown: %8.8XH", lpBmpInfoHdr->biCompression);
  419.         break;
  420.     }
  421.     dprintf4("  biSizeImage:     %lu", lpBmpInfoHdr->biSizeImage);
  422. //  dprintf4("  biXPelsPerMeter: %lu", lpBmpInfoHdr->biXPelsPerMeter);
  423. //  dprintf4("  biYPelsPerMeter: %lu", lpBmpInfoHdr->biYPelsPerMeter);
  424.     dprintf4("  biClrUsed:       %lu", lpBmpInfoHdr->biClrUsed);
  425. //  dprintf4("  biClrImportant:  %lu", lpBmpInfoHdr->biClrImportant);
  426.  
  427. }
  428.  
  429. WORD NumDIBColorEntries(LPBITMAPINFO lpBmpInfo) 
  430. {
  431.     LPBITMAPINFOHEADER lpBIH;
  432.     LPBITMAPCOREHEADER lpBCH;
  433.     WORD wColors, wBitCount;
  434.  
  435.     if (!lpBmpInfo) {
  436.         dprintf1("NULL arg to NumDIBColorEntries()");
  437.         return 0;
  438.     }
  439.  
  440.     lpBIH = &(lpBmpInfo->bmiHeader);
  441.     lpBCH = (LPBITMAPCOREHEADER) lpBIH;
  442.  
  443.     //
  444.     // start off by assuming the color table size from
  445.     // the bit per pixel field
  446.     //
  447.  
  448.     if (IsWinDIB(lpBIH)) {
  449.         wBitCount = lpBIH->biBitCount;
  450.     } else {
  451.         wBitCount = lpBCH->bcBitCount;
  452.     }
  453.  
  454.     switch (wBitCount) {
  455.     case 1:
  456.         wColors = 2;
  457.         break;
  458.     case 4:
  459.         wColors = 16;
  460.         break;
  461.     case 8:
  462.         wColors = 256;
  463.         break;
  464.     case 24:
  465.     default:
  466.         wColors = 0;
  467.         break;
  468.     }
  469.  
  470.     //
  471.     // If this is a Windows DIB, then the color table length
  472.     // is determined by the biClrUsed field
  473.     //
  474.  
  475.     if (IsWinDIB(lpBIH)) {
  476.         if (lpBIH->biClrUsed != 0) {
  477.             wColors = (WORD)lpBIH->biClrUsed;
  478.         }
  479.     }
  480.  
  481.     return wColors;
  482. }
  483.  
  484. //
  485. // Create a DIB the same size and organization as another one
  486. //
  487.  
  488. PDIB CreateCompatibleDIB(PDIB pOld)
  489. {
  490.     PDIB pNew;
  491.  
  492.     pNew = ALLOCATE(SIZE(pOld));
  493.  
  494.     if (!pNew) {
  495.         dprintf1("No memory for new DIB");
  496.         return NULL;
  497.     }
  498.  
  499.     //
  500.     // Copy the bitmap info 
  501.     //
  502.  
  503.     _fmemcpy(pNew,
  504.              pOld, 
  505.              DIB_BISIZE(pOld));
  506.  
  507.     return pNew;
  508. }
  509.  
  510. //
  511. // Map the color table of one DIB to the color table of
  512. // another DIB.  This is used to enure that all sprite DIBs
  513. // are using the same color table as the background DIB so that 
  514. // when we copy sprite DIB bits to the off-screen DIB the colors
  515. // will be correct.
  516. // Note: This is not neccessary if all the sprite DIBs are created 
  517. // with the same palette at authoring time.
  518. //
  519.  
  520. void MapDIBColorTable(PDIB pdibObj, PDIB pdibRef)
  521. {
  522.     PDIB pdibOS;
  523.     LPRGBQUAD pqOS, pqR;
  524.     HDC hdcDIB;
  525.     HPBYTE pBitsS, pBitsD;
  526.     long lScanS;
  527.  
  528.     //
  529.     // Create a DIB compatible with the object DIB
  530.     // and copy the color table of the reference DIB to it
  531.     //
  532.  
  533.     pdibOS = CreateCompatibleDIB(pdibObj);
  534.     if (!pdibOS) return;
  535.  
  536.     pqOS = DIB_PCLRTAB(pdibOS);
  537.     pqR = DIB_PCLRTAB(pdibRef);
  538.     _fmemcpy(pqOS, pqR, 256 * sizeof(RGBQUAD));
  539.  
  540.     //
  541.     // Create a DIB Driver DC from the new DIB
  542.     //
  543.  
  544.     hdcDIB = CreateDC("DIB", NULL, NULL, (LPSTR)pdibOS);
  545.     if (!hdcDIB) {
  546.         dprintf1("Failed to create off-screen DC");
  547.         return;
  548.     }
  549.  
  550.     //
  551.     // Render the object DIB to the off-screen DC using
  552.     // DIB_RGB_COLORS to get the correct color mapping
  553.     //
  554.  
  555.     StretchDIBits(hdcDIB,
  556.                 0,                      // dest x
  557.                 0,                      // dest y
  558.                 DIB_WIDTH(pdibOS),      // dest width
  559.                 DIB_HEIGHT(pdibOS),     // dest height
  560.                 0,                      // src x
  561.                 0,                      // src y
  562.                 DIB_WIDTH(pdibObj),     // src width
  563.                 DIB_HEIGHT(pdibObj),    // src height
  564.                 DIB_PBITS(pdibObj),     // bits
  565.                 DIB_PBI(pdibObj),       // BITMAPINFO
  566.                 DIB_RGB_COLORS,
  567.                 SRCCOPY);               // rop
  568.     //
  569.     // Now copy the bits back from the off-screen DIB
  570.     // to the original DIB
  571.     //
  572.  
  573.     pBitsS = DIB_PBITS(pdibOS);
  574.     pBitsD = DIB_PBITS(pdibObj);
  575.  
  576.     lScanS = DIB_STORAGEWIDTH(pdibOS);
  577.  
  578.     hmemcpy(pBitsD, pBitsS, lScanS * DIB_HEIGHT(pdibOS));
  579.  
  580.     //
  581.     // Delete the off-screen DC and DIB
  582.     //
  583.  
  584.     DeleteDC(hdcDIB);
  585.     DeleteDIB(pdibOS);
  586.  
  587.  
  588.  
  589. }
  590.